import axios from "axios";
import type { InternalAxiosRequestConfig, AxiosResponse } from "axios";
import { useUserStoreHook } from "@/stores/modules/user";
import type { LoginResult } from "@/api/auth/types";
import { clearEmpty } from "@/utils/grpc";
import { ElMessageBox, ElMessage } from "element-plus";
import { vueMetaEnv } from "@/settings";
import type { VueMetaEnv } from "@/types/index";

// 创建 axios 实例
const service = axios.create({
  baseURL: vueMetaEnv.APP_API_URL,
  timeout: 50000,
  headers: { "Content-Type": "application/json;charset=utf-8" }
});

export function axiosConfig(metaEnv: VueMetaEnv) {
  service.defaults.baseURL = metaEnv.APP_API_URL;
}

// 是否正在刷新的标记
let isRefreshing = false;
//重试队列
type TokenCallBackFunc = (token: string) => void;
let requests: TokenCallBackFunc[] = [];

// 请求拦截器
service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    //Grpc Gateway 清理默认值,Enum,时间等不能空;
    clearEmpty(config.params);
    clearEmpty(config.data);

    //配置其他认证请求头信息
    if (config.headers.Authorization === false) {
      delete config.headers.Authorization;
      return config;
    }
    const auth = config.headers.Authorization as string;
    if (auth && auth.length > 0 && !auth.startsWith("Bearer ")) {
      return config;
    }

    //Token.
    const userStore = useUserStoreHook();
    const expire = userStore.isTokenExpires();
    const organTenant = sessionStorage.getItem("OrganTenant:" + userStore.user.tenant);
    //Token正常.
    if (userStore.token && !expire) {
      config.headers.Authorization = "Bearer " + userStore.token;
      if (organTenant && config.headers.GrpcMetadataTenant !== false) {
        config.headers["Grpc-Metadata-Tenant"] = organTenant;
      } else {
        delete config.headers["Grpc-Metadata-Tenant"];
      }
    }

    const refresh_token = config.url == "/v1/rbac/auth/refresh_token";
    //Token已过期或即将过期.
    if (!refresh_token && expire) {
      if (!isRefreshing) {
        isRefreshing = true;
        userStore
          .refreshToken((userStore.userToken as LoginResult).refreshToken!)
          .then((token: string) => {
            // token 刷新后将数组的方法重新执行
            requests.forEach((cb) => cb(token));
            requests = []; // 重新请求完清空
          })
          .catch(() => {})
          .finally(() => {
            isRefreshing = false;
          });
      }
      const retry = new Promise<InternalAxiosRequestConfig<any>>((resolve) => {
        /* (token) => {...}这个函数就是回调函数*/
        requests.push((token) => {
          config.headers.Authorization = "Bearer " + token;
          resolve(config);
        });
      });
      return retry;
    }
    return config;
  },
  (error: any) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    if (response.status === 200) {
      return response;
    } else {
      console.log(response);
      return response;
    }
  },
  (error: any) => {
    if (error.response && error.response.status === 401) {
      // token 过期,重新登录
      ElMessageBox.confirm("当前页面已失效，请重新登录", "提示", {
        confirmButtonText: "确定",
        type: "warning"
      }).then(() => {
        const userStore = useUserStoreHook();
        userStore.resetToken().then(() => {
          location.reload();
        });
      });
      return error.response;
    } else if (error.response && error.response.status === 403) {
      // 403禁止访问
      ElMessage.error("403禁止访问,您没有权限,请联系管理员!");
      return error.response;
    } else if (error.response && error.response.data.code) {
      //一般性错误.
      ElMessage.error(error.response.data.message);
      return error.response;
    } else {
      console.log(error);
      ElMessage.error("网络错误,请联系系统管理员!");
    }
    return Promise.reject(new Error(error));
  }
);

// 导出 axios 实例
export default service;
